package com.codefish.framework.spring.beans.factory;

import com.codefish.framework.spring.beans.annotation.DependencyDescriptor;
import com.codefish.framework.spring.beans.annotation.Value;
import com.codefish.framework.spring.beans.exception.BeanDefinitionException;
import com.codefish.framework.spring.beans.exception.BeansException;
import com.codefish.framework.spring.beans.factory.config.IConfigurableListableBeanFactory;
import com.codefish.framework.spring.beans.factory.support.BeanDefinition;
import com.codefish.framework.spring.beans.factory.support.IBeanDefinitionRegistry;
import com.codefish.framework.spring.core.utils.AssertUtils;
import com.codefish.framework.spring.core.utils.ConvertUtils;
import com.codefish.framework.spring.core.utils.StringUtils;

import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * BeanFactory的一个最终实现
 *
 * @author <a href='https://gitee.com/hzf2281'>codefish</a>
 * @version 1.0.0
 * @since 2022/09/29 下午 01:31
 */
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements IBeanDefinitionRegistry, IConfigurableListableBeanFactory {

    private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);


    @Override
    public BeanDefinition getBeanDefinition(String beanName) {
        return beanDefinitionMap.get(beanName);
    }

    @Override
    public void preInstantiateSingletons() throws BeansException {
        for (Map.Entry<String, BeanDefinition> entry : beanDefinitionMap.entrySet()) {
            String beanName = entry.getKey();
            BeanDefinition bd = entry.getValue();
            if (bd.isSingleton() && !bd.isLazyInit()) {
                //调用getBean()方法，来保证bean被预加载
                getBean(beanName);
            }
        }
    }

    @Override
    public void removeBeanDefinition(String beanName) {
        beanDefinitionMap.remove(beanName);
    }

    @Override
    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) {
        //入参断言校验
        AssertUtils.hasText(beanName, "beanName不能为空");
        AssertUtils.notNull(beanDefinition, "beanDefinition不能为null");
        //TODO 检验beanDefinition的合法性
        //beanDefinition.validate()

        BeanDefinition existBeanDefinition = beanDefinitionMap.get(beanName);
        if (existBeanDefinition != null) {
            if (!isAllowBeanDefinitionOverriding()) {
                throw new BeanDefinitionException("beanDefinition已存在");
            }
            beanDefinitionMap.put(beanName, beanDefinition);
        } else {
            beanDefinitionMap.put(beanName, beanDefinition);
        }
    }

    @Override
    public int getBeanDefinitionCount() {
        return beanDefinitionMap.size();
    }

    @Override
    public List<String> getBeanDefinitionNames() {
        return new ArrayList<>(beanDefinitionMap.keySet());
    }

    @Override
    public List<String> getBeanNamesForType(Class<?> type) {
        if (type == null) {
            return getBeanDefinitionNames();
        }

        return beanDefinitionMap.entrySet().stream().filter(entry -> {
            BeanDefinition bd = entry.getValue();
            return type.isAssignableFrom(bd.getBeanClass());
        }).map(Map.Entry::getKey).collect(Collectors.toList());
    }


    @Override
    public Object resolveDependency(DependencyDescriptor dependencyDescriptor, String requestingBeanName, Set<String> requiredBeanNames) {
        AssertUtils.notNull(dependencyDescriptor, "dependencyDescriptor不能为null");
        return doResolveDependency(dependencyDescriptor, requestingBeanName, requiredBeanNames);
    }

    protected Object doResolveDependency(DependencyDescriptor descriptor, String requestingBeanName, Set<String> requiredBeanNames) {
        Class<?> beanType = descriptor.getDependencyType();
        Object targetValue;
        //解析@Value
        targetValue = getSuggestedValue(descriptor);
        if (targetValue instanceof String) {
            targetValue = resolveEmbeddedValue((String) targetValue);
            if (targetValue != null) {
                //解析的结果为String类型，需要转为对应的beanType类型
                return ConvertUtils.convert((String) targetValue, beanType);
            }
        }
        //解析@Autowired
        List<String> beanNamesForType = getBeanNamesForType(beanType);
        //根据requiredBeanNames决定需要哪个bean
        String determinedBeanName = determiningBeanName(beanNamesForType, requiredBeanNames);
        if (!StringUtils.isEmpty(determinedBeanName)) {
            targetValue = getBean(determinedBeanName);
        }
        return targetValue;
    }

    protected Object getSuggestedValue(DependencyDescriptor descriptor) {
        Annotation[] annotations = descriptor.getAnnotations();
        for (Annotation annotation : annotations) {
            if (annotation instanceof Value) {
                Value valAno = (Value) annotation;
                return valAno.value();
            }
        }
        return null;
    }

    protected String determiningBeanName(List<String> nameList, Set<String> requiredBeanNames) {
        if (nameList == null || nameList.isEmpty()) {
            return null;
        }
        if (requiredBeanNames == null || requiredBeanNames.isEmpty()) {
            return nameList.get(0);
        }
        for (String beanName : nameList) {
            if (requiredBeanNames.contains(beanName)) {
                return beanName;
            }
        }
        return null;
    }


    private boolean isAllowBeanDefinitionOverriding() {
        return false;
    }
}
